/*
 * Copyright 2009-2010 Nanjing RedOrange ltd (http://www.red-orange.cn)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package redora.client.validation;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import redora.client.Service;
import redora.client.ui.RedoraResource;

import java.util.logging.Logger;

import static java.util.logging.Level.SEVERE;

/**
 * BusinessRule check handler in GWT form. It will highlight the field and show
 * error messages if the field do not pass checking.
 *
 * @author Nanjing RedOrange (www.red-orange.cn)
 */
public class BusinessRuleCheckHandler {

    static final transient Logger l = Logger.getLogger("validation.BusinessRuleCheckHandler");
    static RedoraResource resources = GWT.create(RedoraResource.class);

    public static void errorHandler(Element element, String messages) {
        if (element != null)
            element.addClassName(resources.css().redoraBRViolated());
    }

    public static void errorHandler(FlowPanel formTable, String fieldName,
                                    String messages) {
        NodeList<com.google.gwt.dom.client.Element> list = formTable
                .getElement().getElementsByTagName("*");
        Label label = new Label(messages);
        label.addStyleName(resources.css().redoraBRViolated());
        label.getElement().setTitle("errorMessages");
        if (fieldName != null) {
            boolean check = false;
            for (int i = 0; i < list.getLength(); i++) {
                if (list.getItem(i).getId().equalsIgnoreCase(fieldName)) {
                    for (int j = 0; j < formTable.getWidgetCount(); j++) {
                        if (list.getItem(i).equals(formTable.getWidget(j).getElement())) {
                            formTable.insert(label, j + 1);
                        }
                    }
                    list.getItem(i).addClassName(resources.css().redoraBRViolated());
                    // DOM.setElementProperty(list.getItem(i)
                    // .<com.google.gwt.user.client.Element> cast(),
                    // "className", redoraInputValidationFailed.name());
                    check = true;
                }
            }
            if (!check) {
                formTable.insert(label, formTable.getWidgetCount());
            }
        } else {
            formTable.insert(label, formTable.getWidgetCount());
        }
    }

    public static void resetFormStyle(FlowPanel formTable) {
        for (int i = 0; i < formTable.getWidgetCount(); i++) {
            resetStyle(formTable.getWidget(i).getElement());
            if ("errorMessages".equalsIgnoreCase(formTable.getWidget(i)
                    .getTitle())) {
                formTable.remove(i);
                i--;
            }
        }
    }

    public static void resetStyle(Element element) {
        element.removeClassName(resources.css().redoraBRViolated());
    }

    public static boolean hasErrors(JSONObject response
            , final FlowPanel form, DefaultMessageAllocator messageAllocator) {
        resetFormStyle(form);
        switch (Service.ResponseStatus.values()[(int) response.get("status").isNumber().doubleValue()]) {
            case success:
                return false;
            case brViolated:
                JSONArray array = response.get("error").isArray();
                for (int i = 0; i < array.size(); i++) {
                    JSONObject br = array.get(i).isObject();
                    String errorMessage;
                    String objectName = br.get("persistable").isString()
                            .stringValue();
                    String messageId = br.get("businessRuleId").toString();
                    if (br.get("messages") != null) {
                        JSONArray arguments = br.get("messages").isArray();
                        errorMessage = messageAllocator.rule(objectName,
                                Integer.parseInt(messageId), arguments);
                    } else {
                        errorMessage = messageAllocator.rule(objectName,
                                Integer.parseInt(messageId), null);
                    }
                    if (br.get("field") != null) {
                        if (errorMessage == null) {
                            errorMessage = br.get("field").isString().stringValue()
                                    + " is wrong!";
                        }
                        errorHandler(form, br.get("persistable").isString().stringValue()
                                + "." + br.get("field").isString().stringValue(),
                                errorMessage);
                    } else {
                        errorHandler(form, null, errorMessage);
                    }
                }
                return true;
            default:
                l.log(SEVERE, "Unknown response status " + response.get("status").isNumber().doubleValue());
                return true;
        }
    }
}
